﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.Threading;

using BartonExtension;

using Microsoft.AspNet.SignalR;

namespace SignalRService.Model
{
    public class PingPongCounter
    {
        public int count { get; set; }
        public string lastPing { get; set; }
    }
    public class OPIndexedUser
    {
        public string userId { get; set; }
        public string state { get; set; }
    }
    public class OPUser : IDisposable
    {
        private Timer pingpongTimer { get; set; }
        private bool disposed { get; set; }
        private Dictionary<string, PingPongCounter> pingpongTable { get; set; }
        public Action<OPUser,string,bool> actionPing { get; set; }
        public HashSet<string> connections { get; set; }
        public string userId { get; set; }
        public string state { get; set; }
        public bool authorized { get; set; }
        public UserOnlineStatus onlineStatus { get; set; }
        public void AddConnection(string connectionId)
        {
            lock(connections)
            {
                connections.Add(connectionId);
                pingpongTable.Add(connectionId, new PingPongCounter() { count = 0,lastPing = "" });
            }
        }
        public OPUser()
        {
            onlineStatus = UserOnlineStatus.kOnlineStatusDisconnected;
            connections = new HashSet<string>();
            pingpongTable = new Dictionary<string, PingPongCounter>();
            authorized = false;
        }
        public void startPingPong()
        {
            pingpongTimer = new Timer((o) =>
            {
                Ping();
            }, null, 1000, 1000);
        }
        public void ResetPingPongCount(string connectionId)
        {
            if(pingpongTable.ContainsKey(connectionId))
            {
                pingpongTable[connectionId].count = 0;
                pingpongTable[connectionId].lastPing = "";
            }
        }
        private void Ping()
        {
            if(actionPing != null)
            {
                string lastPing = "ping_{0}".FormatWith(IDGenerator.GenerateID());
                bool deleteFlag = false;
                lock (pingpongTable)
                {
                    List<string> willDeleteConnections = new List<string>();
                    foreach(string connectionId in pingpongTable.Keys)
                    {
                        PingPongCounter counter = pingpongTable[connectionId];
                        if (isValidConnection(counter))
                        {
                            counter.lastPing = lastPing;
                        }
                        else
                        {
                            counter.count++;
                            if (counter.count >= Constants.MAX_PING_PONG_RETRY)
                            {
                                willDeleteConnections.Add(connectionId);
                            }
                        }
                    }
                    willDeleteConnections.ForEach(c =>
                    {
                        pingpongTable.Remove(c);
                        connections.Remove(c);
                    });
                    if (connections.Count == 0)
                    {
                        deleteFlag = true;
                    }
                }
                actionPing(this, lastPing,deleteFlag);
            }
        }
        private bool isValidConnection(PingPongCounter counter)
        {
            return counter.lastPing.isNullOrEmpty();
        }

        public void Dispose()
        {
            if (!disposed)
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposed)
            {
                return;
            }
            if (disposing)
            {
                // 清理托管资源
                if(pingpongTimer != null)
                {
                    pingpongTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    pingpongTimer.Dispose();
                    pingpongTimer = null;
                }
                pingpongTable.Clear();
                connections.Clear();
            }
            disposed = true;
        }
    }
}